﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using Csla;
using Csla.Core;
using Itenso.Windows.Input;

using OpenExpressApp.MetaModel;
using OpenExpressApp.Module;
using OpenExpressApp.Module.WPF;
using OpenExpressApp.Module.WPF.Editors;
using OpenExpressApp.Module.WPF.Templete;
using OpenExpressApp.Types;
using OpenExpressApp.WPF.Command;
using OpenExpressApp.WPF.Editors;
using Csla.Reflection;
using OpenExpressApp.Module.WPF.Controls;
using OpenExpressApp.WPF.Controls;
using System.ComponentModel;
using System.Diagnostics;

namespace OpenExpressApp.Module.WPF
{
    /// <summary>
    /// 显示一组对象的列表视图
    /// 
    /// 最主要的功能是对某一实体类型生成对应的列表控件（Control属性）。
    /// </summary>
    public class ListObjectView : WPFObjectView, IListObjectView, IEventListener
    {
        private BusinessObjectsPropertyInfo _bOsPropInfo;

        /// <summary>
        /// ListObjectView主要使用ListEditor来生成控件
        /// </summary>
        private ListEditor _listEditor;

        /// <summary>
        /// 根据某一元素的孩子集合属性的元数据，构造一个ListObjectView
        /// </summary>
        /// <param name="bosPropInfo"></param>
        public ListObjectView(BusinessObjectsPropertyInfo bosPropInfo)
            : this(bosPropInfo.BOType)
        {
            this._bOsPropInfo = bosPropInfo;
            this.PropertyName = bosPropInfo.Name;
        }

        /// <summary>
        /// 为某一类型直接构造一个ListObjectView
        /// </summary>
        /// <param name="boType"></param>
        public ListObjectView(Type boType)
            : base(boType)
        {
            this.CreateEditor(boType);

            var boInfo = ApplicationModel.GetBusinessObjectInfo(boType);
            //查询面板View
            Type condtioQueryType = boInfo.ConditionQueryType;
            if (null != condtioQueryType)
            {
                this._condtionQueryView = new CondtionQueryObjectView(condtioQueryType, this);
                this._condtionQueryView.RegionType = RegionType.ConditionQuery;
            }
            Type navigateQueryType = boInfo.NavigateQueryType;
            if (null != navigateQueryType)
            {
                this.NavigateQueryView = new NavigateQueryObjectView(navigateQueryType, this);
                this.NavigateQueryView.RegionType = RegionType.NavigateQuery;
            }
        }

        /// <summary>
        /// 是否是显示一个树型的列表
        /// </summary>
        public bool IsShowingTree
        {
            get
            {
                return typeof(ITreeNode).IsAssignableFrom(this.BOType);
            }
        }

        /// <summary>
        /// 是否可以被排序
        /// </summary>
        public bool InOrder
        {
            get
            {
                //如果类型有属性OrderNo，则表明需要处理记录顺序号
                return this.BOType.GetProperty(DBConvention.FieldName_OrderNo) != null;
            }
        }

        /// <summary>
        /// 当ListObjectView是用来显示某一对象的孩子对象集合时，
        /// 这个属性表示该孩子集合在父对象中的属性元数据。
        /// </summary>
        public BusinessObjectsPropertyInfo BOsPropInfo
        {
            get
            {
                return this._bOsPropInfo;
            }
        }

        /// <summary>
        /// ListEditor中选择的当前对象
        /// </summary>
        public override object CurrentObject
        {
            get
            {
                //返回控件的值
                var value = this._listEditor.CurrentObject;

                #region 对于显示虚拟数据对象的界面，应该返回真实的对象。

                if (value != null && this.DisplayVisualData)
                {
                    //获取真实的数据。
                    var underlyList = this.UnderlyData;

                    //有可能这时候还没有对DestData赋值，所以再判断一次。
                    if (underlyList != null)
                    {
                        //寻找与这个可视模型对应的内在模型。
                        var displayModel = value as IDisplayModel;
                        Debug.Assert(displayModel != null, "visualModel != null");

                        //没找到，则返回null，说明这个可视模型还没有被“选中”。
                        return underlyList.Cast<IUnderlyModel>()
                            .FirstOrDefault(um => um.IsMappingTo(displayModel));
                    }
                }

                #endregion

                return value;
            }
            set
            {
                var oldObj = this.CurrentObject;
                //todo:不能加以下判断，当操作UI时，CurrentObject＝value导致以下代码不执行而编辑界面绑定对象错误
                if (oldObj != value)
                {
                    //更新控件上的当前选中对象
                    this._listEditor.CurrentObject = value;

                    //更新对应的详细显示界面
                    if (this._detailView != null)
                    {
                        this._detailView.Data = value;
                    }

                    this.OnCurrentObjectChanged();
                }
            }
        }

        public bool IsReadOnly
        {
            get
            {
                return this._listEditor.IsReadOnly;
            }
            set
            {
                this._listEditor.IsReadOnly = value;
            }
        }

        #region ObjectView Relations

        private CondtionQueryObjectView _condtionQueryView;

        private NavigateQueryObjectView _navigateQueryView;

        private DetailObjectView _detailView;

        /// <summary>
        /// 这个ListView可能会有一个 查询面板View
        /// CondtionQueryView 和 NavigateQueryView 只能一个不为空
        /// </summary>
        public CondtionQueryObjectView CondtionQueryView
        {
            get
            {
                return this._condtionQueryView;
            }
        }

        /// <summary>
        /// 这个ListView可能会有导航View
        /// CondtionQueryView 和 NavigateQueryView 只能一个不为空
        /// </summary>
        public NavigateQueryObjectView NavigateQueryView
        {
            get
            {
                return this._navigateQueryView;
            }
            set
            {
                this._navigateQueryView = value;
            }
        }

        /// <summary>
        /// 这个ListView可能还会关联一个DetailView用于显示某一行。
        /// </summary>
        public DetailObjectView DetailView
        {
            get
            {
                return this._detailView;
            }
            set
            {
                this._detailView = value;
            }
        }

        #endregion

        #region Data

        /// <summary>
        /// 是否允许加载数据:如果有导航项，则通过导航项装载数据
        /// </summary>
        protected override bool AllowLoadData
        {
            get
            {
                return base.AllowLoadData && this._navigateQueryView == null;
            }
        }

        /// <summary>
        /// Data 肯定是一组数据，所以返回类型是IList
        /// </summary>
        public new IList Data
        {
            get
            {
                return base.Data as IList;
            }
            set
            {
                Debug.Assert(value == null || value is IList, "value == null || value is IList");

                base.Data = value;
            }
        }

        /// <summary>
        /// 重设置数据源后，当前选择的对象应该清空，重新设置控件的DataContext等
        /// </summary>
        protected override void OnDataChanged()
        {
            var data = this.Data;

            this.ConvertToDisplayData(data);

            //重设置数据源后，当前选择的对象应该清空。
            this.CurrentObject = null;

            this.SetVisibility();

            this._listEditor.NotifyViewDataChanged();

            base.OnDataChanged();
        }

        /// <summary>
        /// 如果这个ListObjectView是细表生成的，则处理它的可见性。
        /// </summary>
        private void SetVisibility()
        {
            //如果是细表生成的，先判断是否可见
            if (this.BOsPropInfo != null && this.BOsPropInfo.IsVisibleAttribute != null)
            {
                //获取当前View所属的TabItem
                TabItem ti = this.Control.GetLogicalParent<TabItem>();
                if (ti != null)
                {
                    //设置Visible的Binding
                    var be = ti.GetBindingExpression(TabItem.VisibilityProperty);
                    if (be == null)
                    {
                        //绑定到IsVisibleAttribute.BindingPath
                        Binding visibleBinding = new Binding(BOsPropInfo.IsVisibleAttribute.PropertyName);
                        visibleBinding.NotifyOnTargetUpdated = true;
                        Binding.AddTargetUpdatedHandler(ti, (o, e) =>
                        {
                            this.IsVisible = e.TargetObject.GetValue(e.Property).Equals(Visibility.Visible);
                        });

                        visibleBinding.Mode = BindingMode.OneWay;
                        visibleBinding.Converter = new BooleanToVisibilityConverter();
                        ti.SetBinding(TabItem.VisibilityProperty, visibleBinding);
                    }

                    //设置DataContext
                    ti.DataContext = this.Parent.CurrentObject;
                }
            }
        }

        #endregion

        #region Selection

        /// <summary>
        /// 选择的对象集合
        /// 
        /// ListEditor中选择的对象集
        /// </summary>
        public IList SelectedObjects
        {
            get
            {
                return this._listEditor.SelectedObjects;
            }
        }

        /// <summary>
        /// 选择全部
        /// </summary>
        public void SelectAll()
        {
            this._listEditor.SelectAll();
        }

        public event EventHandler<SelectedItemChangedEventArgs> SelectedItemChanged;

        /// <summary>
        /// 选择事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void OnSelectedItemChanged(SelectedItemChangedEventArgs e)
        {
            #region 如果是查询导航项,则给相应属性对应的字段按约定赋值

            if (this._bOsPropInfo != null)
            {
                var selectedItem = e.NewItem;
                if (selectedItem != null)
                {
                    //暂时不删除，以后可能需要支持QueryItemValueType枚举
                    //var queryItemAttri = this._bOsPropInfo.QueryItemValueTypeAttribute;

                    //if (queryItemAttri != null)
                    //{
                    //    var valueType = queryItemAttri.QueryItemValueType;
                    //    if (valueType != QueryItemValueType.None)
                    //    {
                    //        var naviView = this.GetRootView() as NavigateQueryObjectView;
                    //        naviView.SetByReferenceEntity(selectedItem);
                    //    }
                    //}

                    var naviView = this.GetRootView() as NavigateQueryObjectView;
                    if (naviView != null)
                    {
                        naviView.SetByReferenceEntity(this.PropertyName, selectedItem);
                    }
                }
            }

            #endregion

            this.SetChildrenData();

            //触发外部事件
            if (this.SelectedItemChanged != null)
            {
                e.View = this;
                this.SelectedItemChanged(this, e);
            }
        }

        #endregion

        #region Underly-Display Object

        /// <summary>
        /// 选择编辑方式下的目标结果数据对象。
        /// 这个数据是真正的对象拥有的数据，而不一定是绑定到控件上面的数据。
        /// </summary>
        private static readonly DependencyProperty DestDataProperty =
            DependencyProperty.RegisterAttached("DestData", typeof(IUnderlyModelList), typeof(ListObjectView));

        /// <summary>
        /// 是否需要间接地使用IDiaplayModel来显示这些数据？
        /// </summary>
        private bool DisplayVisualData
        {
            get
            {
                var assocProperty = this.BOsPropInfo;
                if (assocProperty != null)
                {
                    var assocAttri = assocProperty.AssociationAttribute;
                    if (assocAttri != null)
                    {
                        return assocAttri.AssociationOperateType == AssociationOperateType.Selected;
                    }
                }
                return false;
            }
        }

        /// <summary>
        /// 如果DisplayVisualData是真时，
        /// 那么Data里面存储的是显示的对象列表，
        /// 而这个属性里面存储的是真实的对象列表。
        /// </summary>
        public IUnderlyModelList UnderlyData
        {
            get
            {
                return this.Control.GetValue(DestDataProperty) as IUnderlyModelList;
            }
            private set
            {
                //先设置null，然后再设置为destData，
                //否则有可能在先前已经设置过destData而不会发生PropertyChanged事件。
                var control = this.Control;
                control.SetValue(DestDataProperty, null);
                if (value != null)
                {
                    control.SetValue(DestDataProperty, value);

                    //打开控件的勾选操作功能。
                    var selectableControl = control as ISelectableListControl;
                    if (selectableControl == null) throw new ArgumentNullException("当前控件不支持勾选操作。");
                    selectableControl.SelectionEnabled = true;
                }
            }
        }

        /// <summary>
        /// 导航过滤数据
        /// </summary>
        /// <param name="queryObject">
        /// 通过这个查询对象来过滤数据。
        /// </param>
        public void QueryData(IQueryObject queryObject)
        {
            if (this.Parent.CurrentObject == null)
            {
                return;
            }

            var oldData = this.Parent.CurrentObject.GetPropertyValue(PropertyName);

            if (this.DisplayVisualData == false)
            {
                this.Data = oldData.CallMethod(MethodConvention.GetList, queryObject) as IList;
            }
            else
            {
                //如果是勾选视图，则需要查询出所有用于勾选的数据和已经勾选的数据。
                //这两个数据，可能并不是一个类型。但是一定要保证它们有相同的列。

                var underlyModels = oldData as IUnderlyModelList;
                if (underlyModels == null && oldData != null) throw new ArgumentNullException("列表必须实现IUnderlyModelList接口。");

                //如果实现了过滤，就先把数据过滤一下。
                var filterList = underlyModels as IFilterUnderlyModelList;
                if (filterList != null)
                {
                    underlyModels = filterList.FilterByCriteria(queryObject);
                }

                this.Data = underlyModels.GetDisplayModels(queryObject);
                this.UnderlyData = underlyModels;
            }
        }

        /// <summary>
        /// 装载数据，考虑(AssociationOperateType.Selected
        /// </summary>
        public override void LoadData()
        {
            if (this.DisplayVisualData)
            {
                if (this.AllowLoadData)
                {
                    var parent = this.Parent.CurrentObject as BusinessBase;
                    var data = parent.GetPropertyValue(PropertyName);
                    this.ConvertToDisplayData(data);
                    return;
                }
            }

            base.LoadData();
        }

        /// <summary>
        /// 如果需要转换为显示模型，
        /// 则查找并显示出显示模型，
        /// 然后存储好UnderlyData
        /// </summary>
        /// <param name="data"></param>
        private void ConvertToDisplayData(object data)
        {
            if (this.DisplayVisualData)
            {
                var underlyData = data as IUnderlyModelList;
                if (underlyData != null)
                {
                    var parent = this.Parent.CurrentObject as BusinessBase;
                    this.Data = underlyData.GetDisplayModels(parent);
                    this.UnderlyData = underlyData;
                }
            }
        }

        #endregion

        /// <summary>
        /// 刷新当前对象（包含View中的。）
        /// </summary>
        public override void RefreshCurrentObject()
        {
            this._listEditor.CurrentObject = this.CurrentObject;
            if (this._detailView != null)
            {
                this._detailView.Data = this.CurrentObject;
            }
        }

        /// <summary>
        /// 直接使用Editor生成控件
        /// </summary>
        /// <returns></returns>
        protected override object CreateControl()
        {
            var control = this._listEditor.Control;
            control.SetValue(WPFMeta.ObjectViewProperty, this);
            return control;
        }

        private void CreateEditor(Type boType)
        {
            if (this.IsShowingTree)
            {
                this._listEditor = new ObjectTreeEditor(this, boType);
            }
            else
            {
                this._listEditor = new GridEditor(this, boType);
            }
        }

        #region IListObjectView Members

        IDetailObjectView IListObjectView.DetailView
        {
            get
            {
                return this._detailView;
            }
        }

        void IListObjectView.BindData(object rootPid)
        {
            if (this.IsShowingTree)
            {
                (this._listEditor as ObjectTreeEditor).BindData(rootPid);
            }
        }

        #endregion

        #region IEventListener Members

        void IEventListener.NotifyMouseDoubleClick(object sender, EventArgs e)
        {
            this.OnMouseDoubleClick(e);
        }

        void IEventListener.NotifySelectedItemChanged(object sender, SelectedItemChangedEventArgs e)
        {
            this.OnSelectedItemChanged(e);
        }

        #endregion
    }
}